package com.hong.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.Collections;

@Component
public class RedisLock {

    private final static Logger log = LoggerFactory.getLogger(RedisLock.class);

    private StringRedisSerializer argsStringSerializer = new StringRedisSerializer();
    private StringRedisSerializer resultStringSerializer = new StringRedisSerializer();


    @Autowired
    private RedisTemplate redisTemplate;

//    @Autowired
//    private  DefaultRedisScript redisScript ;

    private final String EXEC_RESULT = "1";

    private final static DefaultRedisScript<String> LOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('set',KEYS[1],ARGV[1],'NX','PX',ARGV[2]) then "
            + " return '1' "
            + "else "
            + "return '0' "
            + "end"
            ,String.class
    );

    private final static DefaultRedisScript<String> UNLOCK_LUA_SCRIPT = new DefaultRedisScript<>(
            "if redis.call('get',KEY[1]) == ARGV[1] then "
                  +"return tostring(redis.call('del',KEYS[1])) "
                  + "else "
                  + "return '0' "
                  + "end"
            ,String.class);





    /**
     * 加锁操作
     * @param key Redis 锁的 key 值
     * @param requestId 请求id，防止解了不该由自己解的锁 (随机生成)
     * @param expireTime 锁的超时时间(毫秒)
     * @param retryTimes 获取锁的重试次数
     * @return true or false
     */
    public boolean lock(String key, String requestId, String expireTime, int retryTimes) {


        if (retryTimes <= 0) {
            retryTimes = 1;
        }
        try {
            int count = 0;
            while (true) {
                String result = (String) redisTemplate.execute(LOCK_LUA_SCRIPT, argsStringSerializer, resultStringSerializer,
                        Collections.singletonList(key), requestId, expireTime);
                log.debug("result:{},type:{}", result, result.getClass().getName());
                if (EXEC_RESULT.equals(result)) {
                    log.info("lock---->result:{},requestId:{}", "加锁成功", requestId);
                    return true;
                } else {
                    count++;
                    if (retryTimes == count) {
                        log.warn("has tried {} times , failed to acquire lock for key:{},requestId:{}", count, key, requestId);
                        return false;
                    } else {
                        log.warn("try to acquire lock {} times for key:{},requestId:{}", count, key, requestId);
                        Thread.sleep(100);
                    }
                }
            }
        } catch (InterruptedException e) {
            log.error("lock---->result:{},requestId:{}", "加锁异常", requestId);
        }
        return false;
    }

    /**
     * 解锁操作
     * @param key Redis 锁的 key 值
     * @param requestId 请求 id, 防止解了不该由自己解的锁 (随机生成)
     * @return true or false
     */
    public boolean unLock(String key, String requestId) {
        String result = (String) redisTemplate.execute(UNLOCK_LUA_SCRIPT, argsStringSerializer, resultStringSerializer,
                Collections.singletonList(key), requestId);
        if (EXEC_RESULT.equals(result)) {
            log.info("unLock---->result:{},requestId:{}", "解锁成功", requestId);
            return true;
        }
        return false;
    }


//    // 简单加锁
//    public  boolean getLock(String key, String requestId, String expireTime) {
//        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/getLock.lua")));
//        Object result = redisTemplate.execute(redisScript,argsStringSerializer,resultStringSerializer, Collections.singletonList(key),requestId,expireTime);
//        if(EXEC_RESULT.equals(result)) {
//            return true;
//        }
//        return false;
//    }
//
//    // 简单解锁
//    public  boolean releaseLock(String key, String requestId) {
//        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("script/releaseLock.lua")));
//        Object result = redisTemplate.execute(redisScript,argsStringSerializer,resultStringSerializer,Collections.singletonList(key),requestId);
//        if(EXEC_RESULT.equals(result)) {
//            return true;
//        }
//        return false;
//    }



}
